#include "lanczosmethod.h"


LanczosMethod::LanczosMethod() :
	// An integer containing the numer of states (the dimension
	// or level d) to use in tri-diagonalization. 
	N_states(1000)
{}


// This operator (use by simply appending () to a KPM type 
// variable) calculates the elements of the tri-diagonalized 
// matrix H_tilde. The operator returns the object it self for 
// easy access to results.
// The result is stored in the alpha and beta result variables. 
LanczosMethod & LanczosMethod::operator()(const sp_cx_mat &H,const  cx_vec &X)
{
	// The result variables are allocated.
	alpha.set_size(N_states);
	beta.set_size(N_states-1);
	
	// The update step is calculated! Note that updateProgress(step)
	// must be called N times = 1/step. This will give a full update 
	// of 1!
	step = 1./(double)(N_states);

	// Three temporary states are allocated: prev, current, and next;
	cx_vec  Xp;			// prev.
	cx_vec  Xc = X;		// current.
	cx_vec  Xn = H*Xc;	// next.

	// Initial params. and state.
	alpha(0) = arma::cdot(Xc,Xn).real();
	Xn = Xn - alpha(0)*Xc; // next.
	beta(0) = arma::norm(Xn,2);
	Xn /= beta(0);

	// Each next state! 
	for(size_t i = 1; i < N_states; i++)
	{
		// Update states.
		Xp = Xc;
		Xc = Xn;
		Xn = H*Xc;
		
		alpha(i) = arma::cdot(Xc,Xn).real();

		if(i == N_states - 1)
		{
			try_updateProgress();
			break;
		}

		Xn = Xn - alpha(i)*Xc - beta(i-1)*Xp; // next.
		beta(i) = arma::norm(Xn,2);
		Xn /= beta(i);
		
		try_updateProgress();
	}
	
	try_updateProgress();

	// That's it!
	return *this;
}

// This function attempts to update the progress.
void LanczosMethod::try_updateProgress() const
{
	if(!updateProgress)
		return;

	updateProgress(step);
}